import Axios, {type AxiosInstance, type AxiosRequestConfig, type AxiosResponse} from 'axios';
import type {Ret} from "@/typings/api";
import {router} from "@/router";
import {MessagePlugin} from "tdesign-vue-next";
import {useAuthStore} from "@/store/modules/auth";

export const baseURL = import.meta.env.DEV ? '/api' : import.meta.env.VITE_BASE_PATH;
const requestTimeout: number = 5 * 1000;

const axiosInstance: AxiosInstance = Axios.create({
    baseURL: baseURL,
    timeout: requestTimeout,
    withCredentials: true
})

//默认config
const baseConfig: AxiosRequestConfig = {
    headers: {
        "Content-Type": "application/json; charset=UTF-8"
    }
};

// 前置拦截器（发起请求之前的拦截）
axiosInstance.interceptors.request.use(config => {
    if (config.url && config.url.startsWith("http")) {
        delete config.baseURL;
    }
    const authStore = useAuthStore();
    if (authStore.token) {
        config.headers[authStore.token.tokenName] = authStore.token.tokenValue;
    }
    return config;
}, error => {
    return Promise.reject(error)
});

// 后置拦截器（获取到响应时的拦截）
axiosInstance.interceptors.response.use(response => {
    if (response?.status === 200) {
        return Promise.resolve(response)
    } else {
        return Promise.reject(response)
    }
}, error => {
    if (error?.message?.includes?.('timeout')) {
        console.error("http", 'timeout')
    } else {
        console.error("http", error)
    }
    Promise.reject(error);
})

/**
 * 组装get\delete请求参数
 * @param map
 */
export const makeParams: Function = (map: Record<string, any> | null): string => {
    if (map == null) {
        return "";
    }
    let str = "?";
    for (let key in map) {
        if (map.hasOwnProperty(key)) {
            if (map[key] != null) {
                str += key + "=" + map[key] + "&";
            }
        }
    }
    str = str.substring(0, str.length - 1);
    return str;
};

const ERROR_CODES: { code: number, message: string }[] = [
    {code: 11001, message: "未能读取到有效Token"},
    {code: 11002, message: "登录时的账号id值为空"},
    {code: 11003, message: "更改 Token 指向的 账号Id 时，账号Id值为空"},
    {code: 11011, message: "未能读取到有效Token"},
    {code: 11012, message: "Token无效"},
    {code: 11013, message: "Token已过期"},
    {code: 11014, message: "Token已被顶下线"},
    {code: 11015, message: "Token已被踢下线"},
    {code: 11016, message: "Token已被冻结"}
];

const isLoginError = (code: number): boolean => {
    for (let i = 0; i < ERROR_CODES.length; i++) {
        if (ERROR_CODES[i].code === code) {
            return true;
        }
    }
    return false;
};

export class HttpUtil {

    static get = <T>(url: string, params?: Record<string, any> | null): Promise<Ret<T>> => {
        const realUrl = (typeof params === "undefined") ? url : (url + makeParams(params));
        return new Promise<Ret<T>>((resolve, reject) => {
            axiosInstance.get(realUrl).then(res => {
                const ret: Ret<T> = res.data;
                if (isLoginError(ret.code)) {
                    const authStore = useAuthStore();
                    if (authStore.isLogin) {
                        authStore.clearToken();
                    }
                    router.replace("/login");
                    MessagePlugin.error(ret.msg);
                }
                resolve(ret);
            }).catch(err => reject(err))
        })
    }

    static getFile = (url: string, params?: Record<string, any> | null): Promise<AxiosResponse> => {
        const config: AxiosRequestConfig = {
            responseType: "blob"
        };
        const realUrl = (typeof params === "undefined") ? url : (url + makeParams(params));
        return new Promise<AxiosResponse>((resolve, reject) => {
            axiosInstance.get(realUrl, config).then(res => {
                resolve(res);
            }).catch(err => reject(err))
        })
    }

    static uploadFile = <T>(url: string, file: File): Promise<Ret<T>> => {
        const formData = new FormData();
        formData.append("file", file);
        const config: AxiosRequestConfig = {
            headers: {
                "Content-Type": "multipart/form-data"
            }
        };
        return new Promise<Ret<T>>((resolve, reject) => {
            axiosInstance.post(url, formData, config).then(res => {
                const ret: Ret<T> = res.data;
                if (isLoginError(ret.code)) {
                    const authStore = useAuthStore();
                    if (authStore.isLogin) {
                        authStore.clearToken();
                    }
                    router.replace("/login");
                    MessagePlugin.error(ret.msg);
                }
                resolve(ret);
            }).catch(err => reject(err))
        })
    }

    static post = <T>(url: string, params: Record<string, any> | null): Promise<Ret<T>> => {
        return new Promise<Ret<T>>((resolve, reject) => {
            axiosInstance.post(url, params, baseConfig).then(res => {
                const ret: Ret<T> = res.data;
                if (isLoginError(ret.code)) {
                    const authStore = useAuthStore();
                    if (authStore.isLogin) {
                        authStore.clearToken();
                    }
                    router.replace("/login");
                    MessagePlugin.error(ret.msg);
                }
                resolve(ret);
            }).catch(err => reject(err))
        })
    }

    static put = <T>(url: string, params: Record<string, any> | null): Promise<Ret<T>> => {
        return new Promise<Ret<T>>((resolve, reject) => {
            axiosInstance.put(url, params, baseConfig).then(res => {
                const ret: Ret<T> = res.data;
                if (isLoginError(ret.code)) {
                    const authStore = useAuthStore();
                    if (authStore.isLogin) {
                        authStore.clearToken();
                    }
                    router.replace("/login");
                    MessagePlugin.error(ret.msg);
                }
                resolve(ret);
            }).catch(err => reject(err))
        })
    }

    static del = <T>(url: string, params?: Record<string, any> | null): Promise<Ret<T>> => {
        const realUrl = (typeof params === "undefined") ? url : (url + makeParams(params));
        return new Promise<Ret<T>>((resolve, reject) => {
            axiosInstance.delete(realUrl, baseConfig).then(res => {
                const ret: Ret<T> = res.data;
                if (isLoginError(ret.code)) {
                    const authStore = useAuthStore();
                    if (authStore.isLogin) {
                        authStore.clearToken();
                    }
                    router.replace("/login");
                    MessagePlugin.error(ret.msg);
                }
                resolve(ret);
            }).catch(err => reject(err))
        })
    }
}
